package code.generate.util;

import code.generate.GenMojo;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author <a href="mailto:hellohesir@gmail.com">Mr_He</a>
 * 2019/3/23 16:53
 */
public class GenerateUtil {

    //表名
    public static String TABLE_NAME;

    //实体名称
    public static String CLASS_NAME;

    //当前时间
    public static String CURRENT_DATE;

    //生成位置 点分割
    public static String PACKAGE_DIR;

    //创建人
    public static String AUTHOR;

    //描述
    public static String DISCRIBE;


    private GenerateUtil() {
    }

    static {
        try {
            /**
             * 使用properties集合读取配置信息
             */
            Properties p = new Properties();
            p.load(new InputStreamReader(new FileInputStream(GenMojo.CODE_DIR), StandardCharsets.UTF_8));

            TABLE_NAME = p.getProperty("table");
            CLASS_NAME = replaceUnderLineAndUpperCase(TABLE_NAME, true);
            PACKAGE_DIR = p.getProperty("package");
            DISCRIBE = p.getProperty("discribe");
            AUTHOR = p.getProperty("author");
            SimpleDateFormat sp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            CURRENT_DATE = sp.format(new Date());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * model
     */
    public static void genModel() throws SQLException, IOException, TemplateException {
        Connection conn = JDBCUtil.getConnection();
        DatabaseMetaData metaData = conn.getMetaData();
        ResultSet resultSet = metaData.getColumns(null, "%", TABLE_NAME, "%");

        ResultSet tables = metaData.getTables(null, "%", TABLE_NAME, null);
        if (!tables.next()) {
            throw new RuntimeException(TABLE_NAME + " 表不存在");
        }

        Map<String, Object> map = new HashMap<>(6);
        map.put("packageDir", PACKAGE_DIR + ".model");
        map.put("author", AUTHOR);
        map.put("time", CURRENT_DATE);
        map.put("tableName", TABLE_NAME);
        map.put("className", CLASS_NAME);

        List<Map<String, String>> columnList = new ArrayList<>();
        while (resultSet.next()) {
            String columnName = resultSet.getString("COLUMN_NAME");
            if (!columnName.equals("update_time") && !columnName.equals("create_time") && !columnName.equals("id")) {
                Map<String, String> columnMap = new HashMap<>(4);
                columnMap.put("typeName", typeSqlToJava(resultSet.getString("TYPE_NAME")));
                columnMap.put("columnName", replaceUnderLineAndUpperCase(columnName, false));
                columnMap.put("msg", resultSet.getString("REMARKS"));
                columnMap.put("rawColumnName", columnName);
                columnList.add(columnMap);
            }

        }
        map.put("columns", columnList);

        String outDir = GenMojo.BASE_DIR + "/src/main/java/" + PACKAGE_DIR.replaceAll("\\.", "/") + "/model/";
        String fileName = map.get("className") + ".java";
        FileUtil.creatFile(outDir, fileName);
        File outFile = new File(outDir + fileName);

        gen("model.ftl", outFile, map);
    }

    /**
     * controller
     */
    public static void genController() throws SQLException, IOException, TemplateException {
        Map<String, Object> map = new HashMap<>(6);
        map.put("packageDir", PACKAGE_DIR);
        map.put("author", AUTHOR);
        map.put("className", CLASS_NAME);
        map.put("classNameLow", replaceUnderLineAndUpperCase(TABLE_NAME, false));
        map.put("discribe", DISCRIBE);
        map.put("time", CURRENT_DATE);

        String outDir = GenMojo.BASE_DIR + "/src/main/java/" + PACKAGE_DIR.replaceAll("\\.", "/") + "/controller/";
        String fileName = CLASS_NAME + "Controller.java";
        FileUtil.creatFile(outDir, fileName);
        File outFile = new File(outDir + fileName);

        gen("controller.ftl", outFile, map);
    }

    /**
     * dao
     */
    public static void genDao() throws SQLException, IOException, TemplateException {
        Map<String, Object> map = new HashMap<>(4);
        map.put("packageDir", PACKAGE_DIR);
        map.put("author", AUTHOR);
        map.put("className", CLASS_NAME);
        map.put("time", CURRENT_DATE);

        String outDir = GenMojo.BASE_DIR + "/src/main/java/" + PACKAGE_DIR.replaceAll("\\.", "/") + "/dao/";
        String fileName = CLASS_NAME + "Dao.java";
        FileUtil.creatFile(outDir, fileName);
        File outFile = new File(outDir + fileName);

        gen("dao.ftl", outFile, map);
    }

    /**
     * service
     */
    public static void genService() throws SQLException, IOException, TemplateException {
        Map<String, Object> map = new HashMap<>(4);
        map.put("packageDir", PACKAGE_DIR);
        map.put("author", AUTHOR);
        map.put("className", CLASS_NAME);
        map.put("time", CURRENT_DATE);

        String outDir = GenMojo.BASE_DIR + "/src/main/java/" + PACKAGE_DIR.replaceAll("\\.", "/") + "/service/";
        String fileName = CLASS_NAME + "Service.java";
        FileUtil.creatFile(outDir, fileName);
        File outFile = new File(outDir + fileName);

        gen("service.ftl", outFile, map);
    }

    /**
     * serviceImpl
     */
    public static void genServiceImpl() throws SQLException, IOException, TemplateException {
        Map<String, Object> map = new HashMap<>(4);
        map.put("packageDir", PACKAGE_DIR);
        map.put("author", AUTHOR);
        map.put("className", CLASS_NAME);
        map.put("time", CURRENT_DATE);

        String outDir = GenMojo.BASE_DIR + "/src/main/java/" + PACKAGE_DIR.replaceAll("\\.", "/") + "/service/impl/";
        String fileName = CLASS_NAME + "ServiceImpl.java";
        FileUtil.creatFile(outDir, fileName);
        File outFile = new File(outDir + fileName);

        gen("serviceImpl.ftl", outFile, map);
    }

    /**
     * 大小写转换
     *
     * @param flag 首字母是否大写
     * @return
     */
    public static String replaceUnderLineAndUpperCase(String str, boolean flag) {
        StringBuffer sb = new StringBuffer();
        sb.append(str);
        int count = sb.indexOf("_");
        while (count != 0) {
            int num = sb.indexOf("_", count);
            count = num + 1;
            if (num != -1) {
                char ss = sb.charAt(count);
                char ia = (char) (ss - 32);
                sb.replace(count, count + 1, ia + "");
            }
        }
        if (flag) {
            String result = sb.toString().replaceAll("_", "");
            return StringUtils.capitalize(result);
        } else {
            return sb.toString().replaceAll("_", "");
        }
    }

    /**
     * 数据类型转化JAVA
     *
     * @param sqlType：数据库类型名称
     */
    public static String typeSqlToJava(String sqlType) {
        if (sqlType == null || sqlType.trim().length() == 0) return sqlType;
        sqlType = sqlType.toLowerCase();
        switch (sqlType) {
            case "nvarchar":
                return "String";
            case "char":
                return "String";
            case "varchar":
                return "String";
            case "text":
                return "String";
            case "nchar":
                return "String";
            case "blob":
                return "byte[]";
            case "integer":
                return "Long";
            case "tinyint":
                return "Integer";
            case "smallint":
                return "Integer";
            case "mediumint":
                return "Integer";
            case "bit":
                return "Boolean";
            case "bigint":
                return "Long";
            case "float":
                return "Fload";
            case "double":
                return "Double";
            case "decimal":
                return "BigDecimal";
            case "boolean":
                return "Boolean";
            case "id":
                return "Long";
            case "date":
                return "Date";
            case "datetime":
                return "Date";
            case "year":
                return "Date";
            case "time":
                return "Time";
            case "timestamp":
                return "Date";
            case "numeric":
                return "BigDecimal";
            case "real":
                return "BigDecimal";
            case "money":
                return "Double";
            case "smallmoney":
                return "Double";
            case "image":
                return "byte[]";
            case "int":
                return "Integer";
            default:
                throw new RuntimeException("转化失败：未发现的类型" + sqlType);
        }
    }

    /**
     * 最终生成
     *
     * @param templateName 模板名称
     * @param file         输出文件
     * @param param        给模板传的参数
     */
    private static void gen(String templateName, File file, Map<String, Object> param) throws IOException, TemplateException {
        Template template = TemplateUtil.getTemplate(templateName);
        FileOutputStream fos = new FileOutputStream(file);
        Writer out = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8), 10240);
        template.process(param, out);
    }
}
